#include "photo_file_server.h"

#include "json-builder.h"

extern "C" {
#include "http_util.h"
#include "file_util.h"
}


PhotoFileServer::PhotoFileServer(PhotoFileServerOption& option):FileServer(option)
{
	if (option.enable_thumbnail) {
//		if (!fs::is_directory(option.thumbnail_directory)) {
//			throw "thumbnail_directory is not a directory";
//		}
		if (option.thumbnail_url.empty()) {
			throw "base_url can't be null";
		}
	}
}

void PhotoFileServer::QueryServerFiles(evhttp_request* req)
{
    enum evhttp_cmd_type cmd_type = evhttp_request_get_command(req);
    if (cmd_type != EVHTTP_REQ_GET) {
        cout << "request type is not Get" << endl;
        return_http_error(req, "request type is not Get");
        return;
    }

    const char* uri = evhttp_request_get_uri(req);
    struct evhttp_uri* evuri = evhttp_uri_parse(uri);
    const char* query = evhttp_uri_get_query(evuri);

    struct evkeyvalq params;
    evhttp_parse_query_str(query, &params);
    const char* start_str = evhttp_find_header(&params, "start");
    const char* limit_str = evhttp_find_header(&params, "limit");
    const char* path_str = evhttp_find_header(&params, "path");

    unsigned int start = 0;
    unsigned int limit = 20;
    fs::path dir_path = _option->base_dirctory;
    fs::path thumbnail_dir_path = std::dynamic_pointer_cast<PhotoFileServerOption>(_option)->thumbnail_directory;

    if (start_str) {
        start = atoi(start_str);
    }
    if (limit_str && atoi(limit_str) > 0) {
        limit = atoi(limit_str);
    }
    if (_option->enable_directory_search && path_str) {
        dir_path = dir_path / path_str;
        thumbnail_dir_path = thumbnail_dir_path / path_str;
    }

    cout << "start is " << start << endl;
    cout << "limit is " << limit << endl;
    cout << "search dir path is " << dir_path << endl;

    vector<FileInfo> fileinfos;
    SearchFileByExts(dir_path, start, limit, _option->exts, fileinfos);

    struct evbuffer* retbuff = evbuffer_new();
    struct evkeyvalq* reqheader = evhttp_request_get_output_headers(req);
    evhttp_add_header(reqheader, "Content-Type", "application/json");
    evhttp_add_header(reqheader, "charset", "UTF-8");

    json_value* top_jv = json_object_new(0);
    json_object_push(top_jv, "status", json_integer_new(200));

    json_value* data_arr_jv = json_array_new(fileinfos.size());
    for (size_t i = 0; i < fileinfos.size(); i++)
    {
        json_value* data_obj_jv = json_object_new(0);
        json_object_push(data_obj_jv, "file_name", json_string_new(fileinfos[i].file_name.c_str()));
        json_object_push(data_obj_jv, "ext", json_string_new(fileinfos[i].extension.c_str()));

        string file_url;
        if (path_str) {
            file_url = _option->base_url + "/" + path_str + "/" + fileinfos[i].file_name;
        }
        else {
            file_url = _option->base_url + "/" + fileinfos[i].file_name;
        }
        json_object_push(data_obj_jv, "url", json_string_new(file_url.c_str()));

        fs::path thumbnail_path;
        string thumbnail_url;
        thumbnail_path = thumbnail_dir_path / fileinfos[i].file_name;
        if (fs::is_regular_file(thumbnail_path)) {
            if (path_str) {
                thumbnail_url = std::dynamic_pointer_cast<PhotoFileServerOption>(_option)->thumbnail_url + "/" + path_str + "/" + fileinfos[i].file_name;
            }
            else {
                thumbnail_url = std::dynamic_pointer_cast<PhotoFileServerOption>(_option)->thumbnail_url + "/" + fileinfos[i].file_name;
            }
        }
        else {
            thumbnail_url = file_url;
        }
        json_object_push(data_obj_jv, "thumbnail_url", json_string_new(thumbnail_url.c_str()));

        json_object_push(data_obj_jv,"file_size",json_integer_new(fileinfos[i].file_size));

        json_object_push(data_obj_jv, "last_write_time", json_integer_new(fileinfos[i].last_write_time));

        json_array_push(data_arr_jv, data_obj_jv);
    }
    json_object_push(top_jv, "data", data_arr_jv);

    json_object_push(top_jv, "start", json_integer_new(start));
    json_object_push(top_jv, "length", json_integer_new(fileinfos.size()));

    size_t json_strlen = json_measure(top_jv);
    char json_str[json_strlen];
    json_serialize(json_str, top_jv);

    json_value_free(top_jv);

#ifdef _WIN32
    size_t utf8_str_len = 100000;
    char utf8_str[utf8_str_len];
    gbk_to_utf8(json_str, utf8_str, utf8_str_len);

    evbuffer_add_printf(retbuff, utf8_str);
    evhttp_send_reply(req, HTTP_OK, "OK", retbuff);
    evbuffer_free(retbuff);
#else
    evbuffer_add_printf(retbuff, json_str);
    evhttp_send_reply(req, HTTP_OK, "OK", retbuff);
    evbuffer_free(retbuff);
#endif
}

void PhotoFileServer::RenameServerFile(evhttp_request* req)
{
    enum evhttp_cmd_type cmd_type = evhttp_request_get_command(req);
    if (cmd_type != EVHTTP_REQ_POST) {
        cout << "request type is not Post" << endl;
        return_http_error(req, "request type is not Post");
        return;
    }

    const char* uri = evhttp_request_get_uri(req);
    struct evhttp_uri* evuri = evhttp_uri_parse(uri);
    const char* query = evhttp_uri_get_query(evuri);

    struct evkeyvalq params;
    evhttp_parse_query_str(query, &params);
    const char* filename = evhttp_find_header(&params, "filename");
    const char* new_filename = evhttp_find_header(&params, "new_filename");

    if (filename == 0 || new_filename == 0) {
        cout << "parameter error" << endl;
        return_http_error(req, "parameter error");
    }

    fs::path file_path = fs::path(_option->base_dirctory) / filename;
    fs::path new_file_path = fs::path(_option->base_dirctory) / new_filename;

    if (!fs::exists(file_path)) {
        cout << "source file is not exist" << endl;
        return_http_error(req, "source file is not exist");
        return;
    }
    if (fs::exists(new_file_path)) {
        cout << "target file is exist" << endl;
        return_http_error(req, "target file is exist");
        return;
    }

    fs::rename(file_path, new_file_path);

    fs::path thumbnail_path = fs::path(std::dynamic_pointer_cast<PhotoFileServerOption>(_option)->thumbnail_directory) / filename;
    fs::path thumbnail_new_path = fs::path(std::dynamic_pointer_cast<PhotoFileServerOption>(_option)->thumbnail_directory) / new_filename;

    if (fs::exists(thumbnail_path)) {
        if (fs::exists(thumbnail_new_path)) {
            fs::remove(thumbnail_new_path);
        }
        fs::rename(thumbnail_path, thumbnail_new_path);
    }

    struct evbuffer* retbuff = evbuffer_new();
    struct evkeyvalq* reqheader = evhttp_request_get_output_headers(req);
    evhttp_add_header(reqheader, "Content-Type", "application/json");
    evhttp_add_header(reqheader, "charset", "UTF-8");

    json_value* top_jv = json_object_new(0);
    json_object_push(top_jv, "status", json_integer_new(200));

    size_t json_strlen = json_measure(top_jv);
    char json_str[json_strlen];
    json_serialize(json_str, top_jv);

    json_value_free(top_jv);
#ifdef _WIN32
    size_t utf8_str_len = 100000;
    char utf8_str[utf8_str_len];
    gbk_to_utf8(json_str, utf8_str, utf8_str_len);

    evbuffer_add_printf(retbuff, utf8_str);
    evhttp_send_reply(req, HTTP_OK, "OK", retbuff);
    evbuffer_free(retbuff);
#else
    evbuffer_add_printf(retbuff, json_str);
    evhttp_send_reply(req, HTTP_OK, "OK", retbuff);
    evbuffer_free(retbuff);
#endif
}